%code top{
    #include <iostream>
    #include <assert.h>
    #include "parser.h"
    #include <cstring>
    #include <stack>
    extern Ast ast;
    int yylex();
    int yyerror(char const*);
    int idx;
    int* arrayValue;
    int leftCnt = 0;
    int paramNo = 0;
    std::stack<StmtNode*> circles;
}

%code requires {
    #include "Ast.h"
    #include "SymbolTable.h"
    #include "Type.h"
}

%union {
    int itype;
    char* strtype;
    StmtNode* stmttype;
    ExprNode* exprtype;
    Type* type;
    SymbolEntry* se;
}

%start Program
%token <strtype> ID STRING
%token <itype> INTEGER
%token IF ELSE WHILE
%token INT VOID
%token LPAREN RPAREN LBRACE RBRACE SEMICOLON LBRACKET RBRACKET COMMA  
%token ADD SUB MUL DIV MOD OR AND LESS LESSEQUAL GREATER GREATEREQUAL ASSIGN EQUAL NOTEQUAL NOT
%token CONST
%token RETURN CONTINUE BREAK

%type<stmttype> Stmts Stmt AssignStmt ExprStmt BlockStmt IfStmt WhileStmt BreakStmt ContinueStmt ReturnStmt DeclStmt FuncDef ConstDeclStmt VarDeclStmt ConstDefList VarDef ConstDef VarDefList FuncFParam FuncFParams MaybeFuncFParams BlankStmt
%type<exprtype> Exp AddExp Cond LOrExp PrimaryExp LVal RelExp EqExp LAndExp MulExp ConstExp UnaryExp InitVal ConstInitVal FuncRParams 
%type<type> Type

%precedence THEN
%precedence ELSE
%%
Program
    : Stmts {
        ast.setRoot($1);
    }
    ;
Stmts
    : Stmt {$$=$1;}
    | Stmts Stmt{
        $$ = new SeqNode($1, $2);
    }
    ;
Stmt
    : AssignStmt {$$=$1;}
    | ExprStmt {$$=$1;}
    | BlockStmt {$$=$1;}
    | BlankStmt {$$=$1;}
    | IfStmt {$$=$1;}
    | WhileStmt {$$=$1;}
    | BreakStmt {
    //增加
        if(circles.size()==0){
            fprintf(stderr, "break is not in while\n");
            assert(circles.size()!=0);
        }
    }
    | ContinueStmt {
        if(circles.size()==0){
            fprintf(stderr, "continue is not in while\n");
            assert(circles.size()!=0);
        }
    }
    | ReturnStmt {$$=$1;}
    | DeclStmt {$$=$1;}
    | FuncDef {$$=$1;}
    ;
LVal
    : ID {
    //增加类型检测，函数标识符不能成为左值
        SymbolEntry* se;
        se = identifiers->lookup($1);
        if(se == nullptr){
            fprintf(stderr, "identifier \"%s\" is undefined\n", (char*)$1);
            delete [](char*)$1;
            assert(se != nullptr);
        }
        else{
            
            if(!((se->getType())->isFunc())){
                $$ = new Id(se);
                delete []$1;
            }
            else{
                fprintf(stderr, "identifier \"%s\" can not be left val\n", (char*)$1);
                assert(!((se->getType())->isFunc()));
            }
        } 
    }
    ; 
AssignStmt
    : LVal ASSIGN Exp SEMICOLON {
        $$ = new AssignStmt($1, $3);
    }
    ;
ExprStmt
    : Exp SEMICOLON {
        $$ = new ExprStmt($1);
    }
    ;
BlankStmt
    : SEMICOLON {
        $$ = new BlankStmt();
    }
    ;
BlockStmt
    : LBRACE {
        identifiers = new SymbolTable(identifiers);
    } 
      Stmts RBRACE {
        $$ = new CompoundStmt($3);
        SymbolTable* top = identifiers;
        identifiers = identifiers->getPrev();
        delete top;
    }
    | LBRACE RBRACE {
        $$ = new CompoundStmt();
    }
    ;
IfStmt
    : IF LPAREN Cond RPAREN Stmt %prec THEN {
        $$ = new IfStmt($3, $5);
    }
    | IF LPAREN Cond RPAREN Stmt ELSE Stmt {
        $$ = new IfElseStmt($3, $5, $7);
    }
    ;
//识别过程中分段识别
WhileStmt
    : WHILE LPAREN Cond RPAREN{
        WhileStmt* whilenode=new WhileStmt($3,nullptr);
        $<stmttype>$ = whilenode;
        circles.push(whilenode);
    } 
    Stmt {
        StmtNode* whilenode=$<stmttype>5;
        ((WhileStmt*)whilenode)->setStmt($6);
        $$=whilenode;
        circles.pop();
    }
    ;
BreakStmt
    : BREAK SEMICOLON {
        $$ = new BreakStmt(circles.top());
    }
    ;
ContinueStmt
    : CONTINUE SEMICOLON {
        $$ = new ContinueStmt(circles.top());
    }
    ;
ReturnStmt
    : RETURN SEMICOLON {
        $$ = new ReturnStmt();
    }
    | RETURN Exp SEMICOLON {
        $$ = new ReturnStmt($2);
    }
    ;
Exp
    :
    AddExp {$$ = $1;}
    ;
Cond
    :
    LOrExp {$$ = $1;}
    ;
PrimaryExp
    : LPAREN Exp RPAREN {
        $$ = $2;
    }
    | LVal {
        $$ = $1;
    }
    | STRING {
        SymbolEntry* se;
        se = globals->lookup(std::string($1));
        if(se == nullptr){
            Type* type = new StringType(strlen($1));
            se = new ConstantSymbolEntry(type, std::string($1));
            globals->install(std::string($1), se);
        }
        ExprNode* expr = new ExprNode(se);

        $$ = expr;
    }
    | INTEGER {
        SymbolEntry* se = new ConstantSymbolEntry(TypeSystem::intType, $1);
        $$ = new Constant(se);
    }
    ;
//增加类型检测：非函数标识符不可被调用
//增加类型检测：实际传入参数与定义不同
UnaryExp 
    : PrimaryExp {$$ = $1;}
    | ID LPAREN FuncRParams RPAREN {
        SymbolEntry* se;
        std::vector<Type*> argus;
        Type* funcType;
        Type* tmp_type;
        ExprNode* temp = (ExprNode*)$3;
        while(temp){
            tmp_type=temp->getSymbolEntry()->getType();
            if(temp->getSymbolEntry()->getType()->isFunc()){
                tmp_type=((FunctionType*)(temp->getSymbolEntry()->getType()))->getRetType();
            }
            argus.push_back(tmp_type);
            temp = (ExprNode*)(temp->getNext());
        }
        se=identifiers->lookup_function($1,argus);
        if(se){
            $$ = new CallExpr(se, $3);
        }
        else{
            fprintf(stderr, "function \"%s\" used with wrong argus\n", (char*)$1);
            delete [](char*)$1;
            assert(se != nullptr);
        }  
    }
    | ID LPAREN RPAREN {
        SymbolEntry* se;
        std::vector<Type*> ept_argus;
        se=identifiers->lookup_function($1,ept_argus);
        if(se == nullptr)
        {
            fprintf(stderr, "function \"%s\" is undefined\n", (char*)$1);
            delete [](char*)$1;
            assert(se != nullptr);
        }
        else{
                $$ = new CallExpr(se);
        }
        
    }
    | ADD UnaryExp {$$ = $2;}
    | SUB UnaryExp {
        //这里的运算要分清是bool还是int
        SymbolEntry* se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
        $$ = new UnaryExpr(se, UnaryExpr::SUB, $2);
    }
    | NOT UnaryExp {
        SymbolEntry* se = new TemporarySymbolEntry(TypeSystem::boolType, SymbolTable::getLabel());
        $$ = new UnaryExpr(se, UnaryExpr::NOT, $2);
    }
    ;
MulExp
    : UnaryExp {$$ = $1;}
    | MulExp MUL UnaryExp {
        SymbolEntry* se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::MUL, $1, $3);
    }
    | MulExp DIV UnaryExp {
        SymbolEntry* se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::DIV, $1, $3);
    }
    | MulExp MOD UnaryExp {
        SymbolEntry* se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::MOD, $1, $3);
    }
    ;
AddExp
    : MulExp {$$ = $1;}
    | AddExp ADD MulExp {
        SymbolEntry* se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::ADD, $1, $3);
    }
    | AddExp SUB MulExp {
        SymbolEntry* se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::SUB, $1, $3);
    }
    ;
//增加：修改关系运算的结果类型为bool
RelExp
    : AddExp {$$ = $1;}
    | RelExp LESS AddExp {
        SymbolEntry* se = new TemporarySymbolEntry(TypeSystem::boolType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::LESS, $1, $3);
    }
    | RelExp LESSEQUAL AddExp {
        SymbolEntry* se = new TemporarySymbolEntry(TypeSystem::boolType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::LESSEQUAL, $1, $3);
    }
    | RelExp GREATER AddExp {
        SymbolEntry* se = new TemporarySymbolEntry(TypeSystem::boolType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::GREATER, $1, $3);
    }
    | RelExp GREATEREQUAL AddExp {
        SymbolEntry* se = new TemporarySymbolEntry(TypeSystem::boolType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::GREATEREQUAL, $1, $3);
    }
EqExp
    : RelExp {$$ = $1;}
    | EqExp EQUAL RelExp {
        SymbolEntry* se = new TemporarySymbolEntry(TypeSystem::boolType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::EQUAL, $1, $3);
    }
    | EqExp NOTEQUAL RelExp {
        SymbolEntry* se = new TemporarySymbolEntry(TypeSystem::boolType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::NOTEQUAL, $1, $3);
    }
    ;

LAndExp
    : EqExp {$$ = $1;}
    | LAndExp AND EqExp {
        SymbolEntry* se = new TemporarySymbolEntry(TypeSystem::boolType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::AND, $1, $3);
    }
    ;
LOrExp
    : LAndExp {$$ = $1;}
    | LOrExp OR LAndExp {
        SymbolEntry* se = new TemporarySymbolEntry(TypeSystem::boolType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::OR, $1, $3);
    }
    ;
ConstExp
    : AddExp {$$ = $1;}
    ;
FuncRParams 
    : Exp {$$ = $1;}
    | FuncRParams COMMA Exp {
        $$ = $1;
        $$->setNext($3);
    }
Type
    : INT {
        $$ = TypeSystem::intType;
    }
    | VOID {
        $$ = TypeSystem::voidType;
    }
    ;
DeclStmt
    : VarDeclStmt {$$ = $1;}
    | ConstDeclStmt {$$ = $1;}
    ;
VarDeclStmt
    : Type VarDefList SEMICOLON {$$ = $2;}
    ;
ConstDeclStmt
    : CONST Type ConstDefList SEMICOLON {
        // 这里肯定还得区分一下 
        $$ = $3;
    }
    ;
VarDefList
    : VarDefList COMMA VarDef {
        $$ = $1;
        $1->setNext($3);
    } 
    | VarDef {$$ = $1;}
    ;
ConstDefList
    : ConstDefList COMMA ConstDef {
        $$ = $1;
        $1->setNext($3);
    }
    | ConstDef {$$ = $1;}
    ;
VarDef
    : ID {
        SymbolEntry* se;
        se = new IdentifierSymbolEntry(TypeSystem::intType, $1, identifiers->getLevel());
        SymbolTable* table=identifiers;
        //此处检查重定义
        if (table->symbolTable.find($1) != table->symbolTable.end()) {
        //找到最近定义域内的同名定义
            fprintf(stderr, "identifier \"%s\" is already defined\n", (char*)$1);
            assert(table->symbolTable.find($1) == table->symbolTable.end());
        }
        else{
            identifiers->install($1, se);
        }
        //结束
        $$ = new DeclStmt(new Id(se));
        delete []$1;
    }
    | ID ASSIGN InitVal {
        SymbolEntry* se;
        SymbolTable* table=identifiers;
        se = new IdentifierSymbolEntry(TypeSystem::intType, $1, identifiers->getLevel());
        //此处检查重定义
        if (table->symbolTable.find($1) != table->symbolTable.end()) {
        //找到最近定义域内的同名定义
            fprintf(stderr, "identifier \"%s\" is already defined\n", (char*)$1);
            assert(table->symbolTable.find($1) == table->symbolTable.end());
        }
        else{
            identifiers->install($1, se);
            ((IdentifierSymbolEntry*)se)->setValue($3->getValue());
            $$ = new DeclStmt(new Id(se), $3);
            delete []$1;
        }
        //结束
    }
    ;
ConstDef
    : ID ASSIGN ConstInitVal {

        SymbolEntry* se;
        se = new IdentifierSymbolEntry(TypeSystem::intType, $1, identifiers->getLevel());
        ((IdentifierSymbolEntry*)se)->setConst();
        //此处检查重定义
        SymbolTable* table=identifiers;
        if (table->symbolTable.find($1) != table->symbolTable.end()) {
        //找到最近定义域内的同名定义
            fprintf(stderr, "identifier \"%s\" is already defined\n", (char*)$1);
            assert(table->symbolTable.find($1) == table->symbolTable.end());
        } 
        else{
            identifiers->install($1, se);
            //printf("7777");
            ((IdentifierSymbolEntry*)se)->setValue($3->getValue());
            $$ = new DeclStmt(new Id(se), $3);
            delete []$1;
        }
        //结束
    }

InitVal 
    : Exp {
        $$ = $1;
    }
    ;

ConstInitVal
    : ConstExp {
        $$ = $1;
    }
    ;
FuncDef
    :
    Type ID {
        identifiers = new SymbolTable(identifiers);
        paramNo = 0;
    }
    LPAREN MaybeFuncFParams RPAREN {
    //函数定义增加对于参数类型的记录
        Type* funcType;
        std::vector<Type*> vec;
        std::vector<SymbolEntry*> pvec;
        DeclStmt* temp = (DeclStmt*)$5;
        while(temp){
            vec.push_back(temp->getId()->getSymbolEntry()->getType());
            pvec.push_back(temp->getId()->getSymbolEntry());
            temp = (DeclStmt*)(temp->getNext());
        }
        funcType = new FunctionType($1, vec,pvec);
        SymbolEntry* se = new IdentifierSymbolEntry(funcType, $2, identifiers->getPrev()->getLevel());
        SymbolTable* table=identifiers->getPrev();
        SymbolEntry* exse;
        Type* tmp_func;
        bool same_func;
        int func_num=0;
        if (table->symbolTable.find($2) != table->symbolTable.end()) {
        //找到最近定义域内的同名定义
            exse = table->symbolTable[$2];
            while(exse){
            //同名定义中如果找到不是函数的，说明重定义
                same_func=true;
                if(!(exse->getType()->isFunc())){
                    fprintf(stderr, "\"%s\" is already defined as a variable\n", (char*)$2);
                    assert((exse->getType()->isFunc()));
                }
                else{
            //如果找到了同名函数定义，则检查参数数量和类型
                    tmp_func=exse->getType();
                    if(((FunctionType*)tmp_func)->paramsType.size()!=vec.size()){
                        exse=exse->getNext();
                        same_func=false;
                        continue;
                    }
                    for(int i=0;i<((FunctionType*)tmp_func)->paramsType.size();i++){
                        if((((FunctionType*)tmp_func)->paramsType[i])->getKind()!=vec[i]->getKind()){
                            same_func=false;
                            break;
                        }
                    }
                    if(same_func){
                        fprintf(stderr, "function \"%s\" is already defined\n", (char*)$2);
                        assert(!same_func);
                    }
                    func_num++;
                    exse=exse->getNext();
                }
            }
        } 
        //将新函数的symbol作为链表头
        if(func_num){
            se->setNext(table->symbolTable[$2]);
            //printf("upuppu\n");
        }
        table->install($2, se);
        //printf("function \n");
        //结束
        
    } 
    BlockStmt {
        SymbolEntry* se;
        se = identifiers->lookup($2);
        assert(se != nullptr);
        $$ = new FunctionDef(se, (DeclStmt*)$5, $8);
        SymbolTable* top = identifiers;
        identifiers = identifiers->getPrev();
        delete top;
        delete []$2;
    }
    ;
MaybeFuncFParams
    : FuncFParams {$$ = $1;}
    | %empty {$$ = nullptr;}
FuncFParams
    : FuncFParams COMMA FuncFParam {
        $$ = $1;
        $$->setNext($3);
    }
    | FuncFParam {$$ = $1;}
    ;
FuncFParam
    : Type ID {
        //bug修改 函数的type为FUNC，与其返回值不同
        SymbolEntry* se;
        se = new IdentifierSymbolEntry($1, $2, identifiers->getLevel(), paramNo++);
        identifiers->install($2, se);
        //debug!!!!!!!!!!!!!!!!!!!
        ((IdentifierSymbolEntry*)se)->setLabel();
        ((IdentifierSymbolEntry*)se)->setAddr(new Operand(se));
        $$ = new DeclStmt(new Id(se));
        delete []$2;
    }
    ;

%%

int yyerror(char const* message)
{
    std::cerr<<message<<std::endl;
    return -1;
}
